﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO.Packaging;
using System.IO;

namespace CPPEI.WebApi.Packaging
{
    public static class PackageUtil
    {
        /// <summary>
        /// 生成压缩文件
        /// </summary>
        /// <param name="destFile">压缩文件路径</param>
        /// <param name="sourceBaseDirectory">源文件的基路径</param>
        /// <param name="sourceFiles">源文件，源文件必须在基目录里</param>
        public static bool Compress(string destFile, string sourceBaseDirectory, string[] sourceFiles)
        {
            bool result = false;
            try
            {
                if (File.Exists(destFile))
                {
                    File.Delete(destFile);
                }

                using (Package package = Package.Open(destFile, System.IO.FileMode.Create))
                {
                    foreach (string sourceFile in sourceFiles)
                    {
                        string relativePath = sourceFile.Replace(sourceBaseDirectory, "/");
                        relativePath = relativePath.Replace("\\", "/");
                        if (!relativePath.StartsWith("/"))
                        {
                            return false;
                        }

                        FileInfo fileInfo = new FileInfo(sourceFile);
                        PackagePart part = package.CreatePart(new Uri(relativePath, UriKind.Relative), System.Net.Mime.MediaTypeNames.Application.Zip);
                        using (FileStream fileStream = new FileStream(sourceFile, FileMode.Open))
                        {
                            fileStream.CopyTo(part.GetStream());
                        }
                    }
                    result = true;
                }

                if (!result)
                {
                    File.Delete(destFile);
                }
            }
            catch(Exception ex)
            {
            }

            return result;
        }

        /// <summary>
        /// 生成压缩文件
        /// </summary>
        /// <param name="destFile"></param>
        /// <param name="sourceDirectory"></param>
        /// <returns></returns>
        public static bool Compress(string destFile, string sourceDirectory)
        {
            List<string> filePaths = new List<string>();
            Stack<DirectoryInfo> dirs = new Stack<DirectoryInfo>();
            dirs.Push(new DirectoryInfo(sourceDirectory));
            while (dirs.Count > 0)
            {
                DirectoryInfo dir = dirs.Pop();
                FileInfo[] files = dir.GetFiles();
                foreach (FileInfo file in files)
                {
                    filePaths.Add(file.FullName);
                }

                DirectoryInfo[] subDirs = dir.GetDirectories();
                foreach (DirectoryInfo subDir in subDirs)
                {
                    dirs.Push(subDir);
                }
            }

            return Compress(destFile, sourceDirectory, filePaths.ToArray());
        }

        public static bool Uncompress(string destDirectory, string zipFilePath)
        {
            if (!File.Exists(zipFilePath))
            {
                return false;
            }

            if (Directory.Exists(destDirectory))
            {
                Directory.Delete(destDirectory, true);
            }
            Directory.CreateDirectory(destDirectory);

            bool result = false;

            try
            {
                using (var package = Package.Open(zipFilePath, FileMode.Open))
                {
                    PackagePartCollection parts = package.GetParts();
                    foreach (PackagePart part in parts)
                    {
                        //这里有一点需要注意的是需要对URL解码
                        string deURL = System.Web.HttpUtility.UrlDecode(part.Uri.OriginalString);
                        string destFilePath = Path.Combine(destDirectory, deURL.Substring(1)).Replace("/", "\\");

                        FileInfo destFileInfo = new FileInfo(destFilePath);
                        if(!destFileInfo.Directory.Exists)
                        {
                            destFileInfo.Directory.Create();
                        }

                        if(destFileInfo.Exists)
                        {
                            destFileInfo.Delete();
                        }

                        using(FileStream fileStream = destFileInfo.Open(FileMode.CreateNew))
                        {
                            part.GetStream().CopyTo(fileStream);
                        }
                    }

                    result = true;
                }
            }
            catch(Exception ex)
            {
                
            }

            if(!result)
            {
                if (Directory.Exists(destDirectory))
                {
                    Directory.Delete(destDirectory, true);
                }
            }
            return result;
        }

        /// <summary>
        /// 从压缩包里读取一个文件
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="fileUrl"></param>
        /// <returns></returns>
        public static Stream ReadFile(string zipFilePath, string fileUrl)
        {
            try
            {
                using (var package = Package.Open(zipFilePath, FileMode.Open))
                {
                    PackagePart part = package.GetPart(new Uri(fileUrl, UriKind.Relative));
                    if(part!=null)
                    {
                        Stream stream = new MemoryStream();
                        part.GetStream().CopyTo(stream);
                        stream.Seek(0, SeekOrigin.Begin);

                        return stream;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            catch(Exception ex)
            {

            }
            return null;
        }
    }
}
